/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GamePlay;

import FrameWork.*;
import FrameWork.Audio.RSAudio;
import FrameWork.Objects.Chacracter.Enemy.House;
import FrameWork.Objects.Chacracter.Enemy.Friend;
import FrameWork.Objects.Chacracter.Enemy.Pig;
import FrameWork.Objects.Chacracter.Enemy.Chicken;
import FrameWork.Objects.Chacracter.Enemy.PigAI;
import FrameWork.Objects.Chacracter.Enemy.ChickenAI;
import FrameWork.Objects.Character.Player;
import FrameWork.Objects.Items.AddBoom;
import FrameWork.Objects.Items.AddHeath;
import FrameWork.Objects.Items.AddLenBoom;
import FrameWork.Objects.Items.AddMaxWater;
import FrameWork.Objects.Items.AddSpeed;
import FrameWork.Objects.Items.Door;
import FrameWork.Objects.Items.Fire;
import FrameWork.Objects.Items.Items;
import FrameWork.Objects.Items.Key;
import FrameWork.Objects.Items.Kick;
import FrameWork.Objects.Items.Water;
import FrameWork.Objects.Items.boom;
import java.io.IOException;
import java.util.Vector;


import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;


/**
*
 * @author ThanhTri
 */
public class State_MainGame extends IState{ 
    
    Vector      m_vEnemy;       // store all enemy
    Vector      m_vItem;        // store all item etc water, fire, pipe, 
    int         m_Map[][];      // store map,brick, for find go
    int         m_Terrain[][];  // Terrain have brick and object don't move over
    
    Player      m_Elefire;        //  Fire man 
    GameScreen m_GameScreen;
    float      m_TimeGame;
    public boolean    m_iMenu;
    boolean    m_iWin;
    boolean    m_iLost;
    State_Lost m_Lost;
    State_Win  m_Win;
    State_MenuInGame m_Menu;
    State_Loading m_Loading;
    ReadMap m_ReadMap  = new ReadMap();
    Sprite m_Ball;
    Rectangle m_Button;
    int m_IDchoosed;
    
    public State_MainGame (IPlay _Play, ReadMap _ReadMap){
        super(_Play);    
        m_IDState = Global.STATE_MAINGAME;
        m_ReadMap = _ReadMap;
    }
    
    public void PointerPressed(int x, int y){
        if(m_iMenu||m_iLost||m_iWin){
            
            if(m_iMenu){
                m_Menu.PointerPressed(x, y);
            }else{
                if(m_iWin){
                    m_Win.PointerPressed(x, y);
                }else{
                    if(m_iLost){
                        m_Lost.PointerPressed(x, y);
                    }
                }
            }   
        }
        else if(m_Button.Intersects(new Point(x, y))){
           RSAudio.getRS().PlayExplosion();
           m_IDchoosed = 1;
           m_iMenu = true;
           m_Menu.Init();     
        } 
    }
    public void MyKey (int _Keycode){
         if(m_iMenu||m_iLost||m_iWin){
            if(m_iMenu){
                m_Menu.KeyPressed(_Keycode);
            }else{
                if(m_iWin){
                    m_Win.KeyPressed(_Keycode);
                }else{
                    if(m_iLost){
                        m_Lost.KeyPressed(_Keycode);
                    }
                }
            }
            
        }else{
            switch(_Keycode)
            {
                // <editor-fold defaultstate="collapsed"  desc="Key : LEFT-RIGHT-UP-DOWN">
                case GameCanvas.UP_PRESSED:
                    m_Elefire.setDirection(Global.DIR_UP);
                    break;
                case GameCanvas.DOWN_PRESSED:
                    m_Elefire.setDirection(Global.DIR_DOWN);
                    break;
                case GameCanvas.RIGHT_PRESSED:
                    m_Elefire.setDirection(Global.DIR_RIGHT);
                    break;
                case GameCanvas.LEFT_PRESSED:
                    m_Elefire.setDirection(Global.DIR_LEFT);
                    break;
            }
        }
        
    }
    public void KeyPressed (int _Keycode){   
        if(m_iMenu||m_iLost||m_iWin){
            
        }else{
            switch(_Keycode)
        {
            case 42:
                RSAudio.getRS().PlayExplosion();
                m_IDchoosed = 1;
                m_iMenu = true;
                m_Menu.Init();
                break; 
            case -5:
            case 53:
                m_Elefire.AddBoom(m_vItem);
                break;
        }
        }
        
    }
    public void Init (){
        try {
            // init resource image
            while ( (RSMainGame.getRS().Init()>=0));
            
            m_Ball = new Sprite (Image.createImage("/Image/bubble.png"),
                            90, 90);
            
            m_Button = new Rectangle(-33, -50, 90, 90);
            m_IDchoosed = 0;
            
            m_iMenu = false;
            m_iLost = false;
            m_iWin  = false;
            
            m_Lost = new State_Lost(m_Play, this);
            m_Win = new State_Win(m_Play, this);
            m_Menu = new State_MenuInGame(m_Play, this);
            
            m_Lost.Init();
            m_Win.Init();
            m_Menu.Init();
            
           
            m_vItem = new Vector();
            m_vEnemy = new Vector();
           
            // < editor-fold defaultstate="collapsed" desc="Copy data form level to list enemy and item ">
            m_Map = m_ReadMap.getMap();
            m_TimeGame = m_ReadMap.getTime();
            m_Terrain =new int[m_ReadMap.getWidth()][m_ReadMap.getHeight()];
            for (int i = 0; i < m_ReadMap.getWidth(); i++) {           
                for (int j = 0; j < m_ReadMap.getHeight(); j++) {     
                    switch ( m_Map [i][j]){
                        case Global.ID_WATER:
                           m_vItem.addElement(
                                    new Water(i, j, 30,30, 0.2f, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_WATER));
                                m_Map[i][j]=Global.ID_EMPTY;
                            break;
                            case Global.ID_DOOR:
                                m_vItem.addElement(
                                    new Door(i, j, 30,30, 0.2f, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_DOOR));
                                m_Map[i][j]=Global.ID_EMPTY;
                            break;
                         case Global.ID_FIRE:
                    try {
                        m_vItem.addElement(
                                 new Fire(m_vItem,i, j, 30, 30, 0.2f, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_FIRE));
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                           m_Map[i][j]=Global.ID_EMPTY;
                            break;      
                        case Global.ID_FRIEND:                       
                    try {
                        m_vEnemy.addElement(
                                 new Friend(i, j, 30, 30, 0.2f,
                                Global.SPEED_LOW,
                                Global.DIR_DOWN, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),
                                Global.ID_FRIEND));
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                           m_Map[i][j]=Global.ID_EMPTY;
                            break;  
                            
                        case Global.ID_KEY:
                           m_vItem.addElement(
                                    new Key(i, j, 30, 30, 0.2f,m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_KEY));
                           m_Map[i][j]=Global.ID_EMPTY;
                            break; 
                        case Global.ID_KICK:
                           m_vItem.addElement(
                                    new Kick(i, j, 30, 30, 0.2f,m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_KICK));
                           m_Map[i][j]=Global.ID_EMPTY;
                            break; 
                        case Global.ID_ADD_BOOM:
                           m_vItem.addElement(
                                    new AddBoom(i, j, 30, 30, 0.2f,m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_ADD_BOOM));
                           m_Map[i][j]=Global.ID_EMPTY;
                            break; 
                        case Global.ID_ADD_LENGHTBOOM:
                           m_vItem.addElement(
                                    new AddLenBoom(i, j, 30, 30, 0.2f,m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_ADD_LENGHTBOOM));
                           m_Map[i][j]=Global.ID_EMPTY;
                            break; 
                        case Global.ID_ADD_MAXWATER:
                           m_vItem.addElement(
                                    new AddMaxWater(i, j, 30, 30, 0.2f,m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_ADD_MAXWATER
                                   ));
                           m_Map[i][j]=Global.ID_EMPTY;
                            break; 
                        case Global.ID_ADD_HP:
                           m_vItem.addElement(
                                    new AddHeath(i, j, 30, 30, 0.2f,m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_ADD_HP
                                   ));
                           m_Map[i][j]=Global.ID_EMPTY;
                            break; 
                        case Global.ID_ADD_SPEED:
                           m_vItem.addElement(
                                    new AddSpeed(i, j, 30, 30, 0.2f,m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),Global.ID_ADD_SPEED));
                           m_Map[i][j]=Global.ID_EMPTY;
                            break;
                        case Global.ID_PIG:
                            m_vEnemy.addElement(
                                 new Pig(i, j, 30, 30, 0.2f,
                                Global.SPEED_LOW,
                                Global.DIR_DOWN, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),
                                Global.ID_PIG));
                            m_Map[i][j]=Global.ID_EMPTY;
                            break;
                        case Global.ID_CHICKEN:
                            m_vEnemy.addElement(
                                 new Chicken(i, j, 30, 30, 0.2f,
                                Global.SPEED_LOW,
                                Global.DIR_DOWN, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),
                                Global.ID_CHICKEN));
                            m_Map[i][j]=Global.ID_EMPTY;
                            break;
                        case Global.ID_PIGAI:
                            m_vEnemy.addElement(
                                 new PigAI(i, j, 30, 30, 0.2f,
                                Global.SPEED_LOW,
                                Global.DIR_DOWN, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),
                                Global.ID_PIGAI));
                            m_Map[i][j]=Global.ID_EMPTY;
                            break;
                        case Global.ID_CHICKENAI:
                            m_vEnemy.addElement(
                                 new ChickenAI(i, j, 30, 30, 0.2f,
                                Global.SPEED_LOW,
                                Global.DIR_DOWN, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),
                                Global.ID_CHICKENAI));
                            m_Map[i][j]=Global.ID_EMPTY;
                            break;
                        case Global.ID_HOUSE:                       
                        m_vEnemy.addElement(
                                new House
                                (i, j, 90, 90, 0.2f, 0,
                                Global.DIR_DOWN, m_Map,
                                m_ReadMap.getWidth(),m_ReadMap.getHeight(),
                                Global.ID_HOUSE));
                          m_Map[i][j]=Global.ID_EMPTY;
                          
                            break;
                        }                       
                    }               
                }
             // </editor-fold>
            
            //<editor-fold defaultstate="collapsed" desc="Init GameScreen">
            m_GameScreen = new GameScreen(m_Graphics,
                    new Rectangle(0,0,8*30,11*30),m_ReadMap);
            //</editor-fold>
            
            //<editor-fold defaultstate="collapsed" desc="Init character">
            m_Elefire = new Player(m_ReadMap.getFigures()[0],
                    m_ReadMap.getFigures()[1], 30, 30,
                    Global.TIME_ANIMATION,Global.SPEED_NORMAL,
                    Global.DIR_RIGHT, m_Map,
                    m_ReadMap.getWidth(),m_ReadMap.getHeight(),
                    Global.ID_FIREMAN);
            //</editor-fold>
            
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        RSAudio.getRS().PlayBack();
    }
    public void Update (float _Time){
        if(m_iMenu||m_iLost||m_iWin){
            if(m_iMenu){
                m_Menu.Update(_Time);
            }else{
                if(m_iWin){
                    m_Win.Update(_Time);
                }else{
                    if(m_iLost){
                        m_Lost.Update(_Time);
                    }
                }
            }
            
        }else{
            m_TimeGame-=_Time;
            MergeTerrain();

            //<editor-fold defaultstate="collapsed" desc="Fireman Update">
            m_Elefire.Update(_Time,m_Terrain);
            m_Elefire.ActiveItems(m_vItem); 

            //<editor-fold defaultstate="collapsed" desc="Update and collision item">
           UpdateItem(_Time);
           //</editor-fold>  

            UpdateEnemy(_Time);

    //        CollisonItemEnemy();

            //<editor-fold defaultstate="collapsed" desc="Update Screen">
            m_GameScreen.UpdateMove(m_Elefire);
            //</editor-fold>

            CheckWinLost();
        }
        
    }
    
    public void Render (){
        
        //<editor-fold defaultstate="collapsed" desc="Clear screen">
        m_Graphics.setColor(153, 157, 15);
        m_Graphics.fillRect(0, 0, 240, 320);
        //</editor-fold>
        
        //<editor-fold defaultstate="collapsed" desc="Render map and brick">
        for (int i = 0; i < m_ReadMap.getWidth(); i++) {
            for (int j = 0; j < m_ReadMap.getHeight(); j++) {
                    switch(m_Map[i][j]){
                        case Global.ID_GRASS:
                             Rectangle rb = new Rectangle(i*30, j*30, 30, 30);
                            if(rb.Intersects(m_GameScreen.getRect())){
                                RSMainGame.getRS().getItem().setFrame(0);
                                RSMainGame.getRS().
                                        getItem().setPosition(i*30 - (m_GameScreen.getXView() - m_GameScreen.getWidth()/2),
                                        j*30 -(m_GameScreen.getYView() - m_GameScreen.getHeight()/2));
                                RSMainGame.getRS().getItem().paint(m_Graphics);
                            }
                            break;
                    }
            }
        }
        //</editor-fold>
        
        //<editor-fold defaultstate="collapsed" desc="Render Item">
        for (int i = 0; i < m_vItem.size(); i++) {
            
            Items t = (Items)m_vItem.elementAt(i);
            if(t.getID() == Global.ID_BOOM){
                boom b = (boom) t;
                if(b.Intersect(m_GameScreen.getRect())){
                    t.DrawScreen(m_Graphics, m_GameScreen); 
                }
            }else{
               if (t.getRect().Intersects(m_GameScreen.getRect())){
                    t.DrawScreen(m_Graphics, m_GameScreen); 
                } 
            }
        }
        //</editor-fold>
        
        //<editor-fold defaultstate="collapsed" desc="Render Friend">
        for (int i = 0; i < m_vEnemy.size(); i++) {
            
            Friend enemy = (Friend)m_vEnemy.elementAt(i);
            if (enemy.getRect().Intersects(m_GameScreen.getRect())){
                enemy.DrawScreen(m_Graphics, m_GameScreen);
            }
            
        }
        //</editor-fold>
        
        m_Elefire.DrawScreen(m_Graphics, m_GameScreen); 
       
        RenderUI();
        
         if(m_iMenu||m_iLost||m_iWin){
            if(m_iMenu){
                m_Menu.Render();
            }else{
                if(m_iWin){
                    m_Win.Render();
                }else{
                    if(m_iLost){
                        m_Lost.Render();
                    }
                }
            }
        }
        
    }
    public void Destroy (){        
        m_vEnemy.removeAllElements();
        m_vItem.removeAllElements();
        Level.get().saveData();
        m_Ball = null;
    }
    
   public void RenderUI (){
       
       RSFont.getRS().getLarge().DrawString("pause",
                0, 3, m_Graphics);
       Sprite UI = RSMainGame.getRS().getUI();
        UI.setPosition(0, 270);
        UI.paint(m_Graphics);
        if(Level.get().getCurLevel()<10)
            RSFont.getRS().getFont(Global.FONT_BIG).DrawString(
                                "LEVEL:" + Level.get().getCurLevel(), 170, 3, getGraphics());
        else
            RSFont.getRS().getFont(Global.FONT_BIG).DrawString(
                                "LEVEL:" + Level.get().getCurLevel(), 165, 3, getGraphics());
        if(m_IDchoosed == 0){
            m_Ball.setFrame(0);
            m_Ball.setPosition(-33, -50);
            m_Ball.paint(m_Graphics);
        }else{
            m_Ball.setFrame(1);
            m_Ball.setPosition(-33, -50);
            m_Ball.paint(m_Graphics);
        }
            
        
        RSFont.getRS().getLarge().DrawString(""+m_Elefire.m_HP,
                14, 290, m_Graphics);
        
        RSFont.getRS().getLarge().DrawString(m_Elefire.m_NumWater+"/"+m_Elefire.m_MaxWater,
                50, 290, m_Graphics);
        
        if(m_Elefire.m_iKick==true){
                RSMainGame.getRS().getItem().setFrame(18);
                RSMainGame.getRS().getItem().setPosition( 105,280);
                RSMainGame.getRS().getItem().paint(m_Graphics);
        }
        
        RSFont.getRS().getLarge().DrawString(""+(m_Elefire.m_MaxBoom - m_Elefire.m_vBoom.size()),
                116, 290, m_Graphics);
        
        if (m_TimeGame>20) {
            if(m_TimeGame>=100){
                RSFont.getRS().getLarge().DrawString("" + (int) m_TimeGame,
                   204, 290, m_Graphics);
            }else{
                RSFont.getRS().getLarge().DrawString("" + (int) m_TimeGame,
                   207, 290, m_Graphics);
            }
           
       } else {
            if(m_TimeGame>=10){
                if(System.currentTimeMillis()%(800) >=300){
                 RSFont.getRS().getLarge().DrawString("" + (int) m_TimeGame,
                   207, 290, m_Graphics);
                }
            }else{
                if(System.currentTimeMillis()%(500) >=200){
                 RSFont.getRS().getLarge().DrawString("" + (int) m_TimeGame,
                   212, 290, m_Graphics);
                }
            }
            
       }
        
        
        if(m_Elefire.m_iKey==true){
            if(System.currentTimeMillis()%1000<600){
                RSMainGame.getRS().getItem().setFrame(19);
                RSMainGame.getRS().getItem().setPosition( 155,280);
                RSMainGame.getRS().getItem().paint(m_Graphics);
            }
        }
   }
    public void CheckWinLost(){
        //<editor-fold defaultstate="collapsed" desc="Lost">
        if(iLost()){
            m_iLost = true;
        }
        //</editor-fold>
        
        //<editor-fold defaultstate="collapsed" desc="Win">
        if(iWin()){
            m_iWin = true;
        }
        //</editor-fold>
    }
    
    public boolean iLost (){
         //<editor-fold defaultstate="collapsed" desc="ElefireHP">
        if(m_Elefire.getSTATUS()==Global.STT_DEATH){
            return true;
//            m_Play.setNextState(new State_Menu(m_Play));
        }
        if(m_TimeGame<0){
            return true;
        }
        //</editor-fold>
        return false;
    }
    public boolean iWin (){
        for (int i = 0; i < m_vItem.size();i++) {
            Items Item = (Items)m_vItem.elementAt(i);
            if(Item.getSTATUS()!= Global.STT_DEATH && Item.getID() == Global.ID_FIRE ){
                return false;
            }
        }
        for (int i = 0; i < m_vEnemy.size();i++) {
            Friend enemy = (Friend)m_vEnemy.elementAt(i);
            if(enemy.getSTATUS()== Global.STT_ACTIVE || 
                    enemy.getSTATUS() == Global.STT_INVI){
                return false;
            }
        }
        return true;
    }
    
    public void MergeTerrain(){
        
        //<editor-fold defaultstate="collapsed" desc="map">
        for (int i = 0; i < m_ReadMap.getWidth(); i++) {
            for (int j = 0; j < m_ReadMap.getHeight(); j++) {
                m_Terrain[i][j]=m_Map[i][j];
            }
        }
        //</editor-fold>
        
        //<editor-fold defaultstate="collapsed" desc="Item">
        for (int i = 0; i < m_vItem.size();i++) {
            Items Item = (Items)m_vItem.elementAt(i);
            if(Item.getSTATUS()!= Global.STT_DEATH ){
                switch(Item.getID()){
                    case Global.ID_BOOM:
                        m_Terrain[Item.getX()][Item.getY()]= Item.getID();
                        break;
                    case Global.ID_DOOR:
                        m_Terrain[Item.getX()][Item.getY()]= Item.getID();
                        break;
                }
            }
        }
        //</editor-fold>
        
        //<editor-fold defaultstate="collapsed" desc="enemy">
        for (int i = 0; i < m_vEnemy.size();i++) {
            Friend enemy = (Friend)m_vEnemy.elementAt(i);
                switch(enemy.getID()){
                    case Global.ID_HOUSE:
                        for (int j = 0; j < 3; j++) {
                            if(enemy.getX()+j >= m_ReadMap.getWidth()){
                                break;
                            }
                            for (int k = 0; k < 3; k++) {
                                if(enemy.getY()+k >= m_ReadMap.getHeight()){
                                    break;
                                }
                                m_Terrain[enemy.getX()+j][enemy.getY()+k]= enemy.getID();
                            }
                        }
                        break;
            }
        }
        //</editor-fold>
    }
    
    public void UpdateItem (float _Time){
        for (int i = 0; i < m_vItem.size();) {
           Items Item = (Items)m_vItem.elementAt(i);
           if(Item.getSTATUS()== Global.STT_DEATH &&
                   Item.getOldStatus()==Global.STT_DEATH){
               m_vItem.removeElementAt(i);
               
           }else{
               i++;
               Item.Update(_Time,m_Terrain);
               
               //<editor-fold defaultstate="collapsed" desc="Elefre">
               if(Item.getRect().Intersects(m_Elefire.getRect())){
                   m_Elefire.ActionCollision(Item);
                   Item.ActionCollision(m_Elefire);
               }
               //</editor-fold>
                
               //<editor-fold defaultstate="collapsed" desc="boom expltion">
                if(Item.getID()== Global.ID_BOOM_EXPLOSION){
                    for (int j = 0; j < m_vItem.size();j++) {
                        if(j==i)continue;
                        Items ItemJ = (Items)m_vItem.elementAt(j);
                        if(Item.getRect().Intersects(ItemJ.getRect())){
                            ItemJ.ActionCollision(Item);
                        }
                        
                    }
                }
                //</editor-fold>
                
           }
           
       }
    }

    public void setIDchoosed(int m_IDchoosed) {
        this.m_IDchoosed = m_IDchoosed;
    }
    
    public void UpdateEnemy (float _Time){
        // <editor-fold defaultstate="collapsed" desc="Update and collision enemy">
        for (int i = 0; i < m_vEnemy.size(); i++) {           
            Friend enemy = (Friend)m_vEnemy.elementAt(i);
              enemy.Update(_Time, m_Terrain);           
              enemy.UpdateAI(_Time, m_Elefire, m_vEnemy, m_Terrain);
              
              //<editor-fold defaultstate="collapsed" desc="elefire">
              if(enemy.getSTATUS()== Global.STT_ACTIVE&&
                      enemy.getRect().Intersects(m_Elefire.getRect())){
                  m_Elefire.ActionCollision(enemy);
                  enemy.ActionCollision(m_Elefire);
              }
              //</editor-fold>
              
              //<editor-fold defaultstate="collapsed" desc="enemys">
              for (int j = i; j < m_vEnemy.size();j++) {
                  Friend enemyJ = (Friend)m_vEnemy.elementAt(j);
                  if(enemy.getRect().Intersects(enemyJ.getRect())){
                      enemy.ActionCollision(enemyJ);
                      enemyJ.ActionCollision(enemy);
                  }
              }
              //</editor-fold>
              
              for (int j = 0; j < m_vItem.size();j++) {
                Items ItemJ = (Items)m_vItem.elementAt(j);
                if(ItemJ.getID()!= Global.ID_BOOM_EXPLOSION&&
                        ItemJ.getID()!= Global.ID_FIRE) continue;
                if(enemy.getRect().Intersects(ItemJ.getRect())){
                    enemy.ActionCollision(ItemJ);
                }
           }
              
        }
        // </editor-fold>
    }
}
